﻿#pragma once

#include "detail/sys_logger_impl.hh"
#include "klogger/interface/logger.h"
#include "lang/lang.hh"
#include "util/box_flow.hh"
#include "util/box_std_allocator.hh"
#include "util/object_pool.hh"

#include "box_network.hh"

#include <cstdint>
#include <ctime>
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace rpc {
class Transport;
class Rpc;
class RpcImpl;
class StubCall;
class Stub;
class Proxy;
class ProxyHandlerImpl;
class RpcProbe;
} // namespace rpc

namespace kratos {
namespace config {
class BoxConfigImpl;
}
} // namespace kratos

namespace kratos {
namespace argument {
class BoxArgumentImpl;
class BoxArgument;
} // namespace argument
} // namespace kratos

namespace klogger {
class Logger;
class Appender;
} // namespace klogger

namespace kratos {
namespace lang {
class Lang;
class LangImpl;
} // namespace lang
} // namespace kratos

namespace kratos {
namespace console {
class ConsoleImpl;
} // namespace console
} // namespace kratos

namespace kratos {
namespace util {
class ModuleLoader;
class BoxFlowManager;
} // namespace util
} // namespace kratos

namespace kratos {
namespace component {
class ComponentFactoryImpl;
}
} // namespace kratos

namespace kratos {
namespace service {

class ServiceFinder;
class ServiceFinderImpl;
class ServiceRegister;
class ServiceRegisterImpl;
class BoxNetwork;
class ServiceContextImpl;
class ServiceContext;
class ServiceBox;
class RpcLoggerImpl;
class ServiceHttpLoader;
class CommandManager;
class ProcStat;
class ProcStatImpl;
class LocalCommand;
class SysLoggerImpl;
class TimerFactoryImpl;
class ServiceLayer;
class DebugServerImpl;
class InterfaceDescriptorFactoryImpl;
class RpcProbeImpl;
class LimiterManager;
class ServiceMechManager;

using ModuleLoaderPtr = std::shared_ptr<util::ModuleLoader>;
using TransportPtr = std::shared_ptr<rpc::Transport>;
using ConStrRef = const std::string &;
using ServiceFinderPtr = std::shared_ptr<ServiceFinder>;
using ServiceRegisterPtr = std::shared_ptr<ServiceRegister>;
using BoxConfigImplPtr = unique_pool_ptr<config::BoxConfigImpl>;
using BoxArgumentImplPtr = unique_pool_ptr<argument::BoxArgumentImpl>;
using ServiceHttpLoaderPtr = unique_pool_ptr<ServiceHttpLoader>;
using ServiceContextImplPtr = unique_pool_ptr<ServiceContextImpl>;
using RpcLoggerImplPtr = unique_pool_ptr<RpcLoggerImpl>;
using LangImplPtr = unique_pool_ptr<lang::LangImpl>;
using LocalCommandPtr = unique_pool_ptr<LocalCommand>;
using CommandManagerPtr = unique_pool_ptr<CommandManager>;
using ProcStatImplPtr = unique_pool_ptr<ProcStatImpl>;
using SysLoggerImplPtr = unique_pool_ptr<SysLoggerImpl>;
using ProxyHandlerImplPtr = unique_pool_ptr<rpc::ProxyHandlerImpl>;
using ConsoleImplPtr = unique_pool_ptr<console::ConsoleImpl>;
using ServiceLayerPtr = unique_pool_ptr<ServiceLayer>;
using TimerFactoryImplPtr = unique_pool_ptr<TimerFactoryImpl>;
using InterfaceDescriptorFactoryImplPtr =
    unique_pool_ptr<InterfaceDescriptorFactoryImpl>;
using DebugServerImplPtr = unique_pool_ptr<DebugServerImpl>;
using RpcProbeImplPtr = unique_pool_ptr<RpcProbeImpl>;
using RpcImplPtr = unique_pool_ptr<rpc::RpcImpl>;
using ConBoxArgumentRef = const argument::BoxArgument &;
using BoxConfigRef = config::BoxConfig &;
using ConBoxConfigRef = const config::BoxConfig &;
using LimiterManagerPtr = std::shared_ptr<LimiterManager>;
using BoxFlowManagerPtr = std::shared_ptr<util::BoxFlowManager>;
using ComponentFactoryPtr = unique_pool_ptr<component::ComponentFactoryImpl>;
using ServiceMechManagerPtr = std::shared_ptr<ServiceMechManager>;

/**
 * 注册上线文
 */
class RegisterContext {
public:
  virtual ~RegisterContext() {}
  /**
   * 获取服务注册/发现工厂管理器
   */
  virtual auto get_service_mech_manager() -> ServiceMechManager * = 0;
};

/**
 * \brief 服务容器.
 * 加载并运行服务，提供跨平台的运行能力，包含服务发现，服务远程调用，服务更新等功能
 */
class ServiceBox : public BoxNetwork, public RegisterContext {
private:
  using StringMap = PoolUnorederedMap<std::string, std::string>;
  using StringSet = PoolUnorderedSet<std::string>;
  using StringVector = std::vector<std::string>;
  using ModuleVector = PoolVector<ModuleLoaderPtr>;

  constexpr static char const *CONSOLE_LOGGER_CONFIG_LINE =
      "console://;line=[%y%m%d-%H:%M:%S:%U];flush=true"; ///< console日志默认配置

  ServiceFinderPtr service_finder_;       ///< 服务发现
  ServiceRegisterPtr service_register_;   ///< 服务注册
  BoxConfigImplPtr box_config_;           ///< 配置
  BoxArgumentImplPtr box_argument_;       ///< 命令行参数
  ServiceHttpLoaderPtr http_loader_;      ///< 服务更新
  ServiceContextImplPtr service_context_; ///< 暴露给用户的调用上下文
  RpcLoggerImplPtr rpc_logger_;           ///< RPC日志
  LangImplPtr lang_;                      ///< 多国语言
  LocalCommandPtr local_command_;         ///< 本地命令
  CommandManagerPtr command_manager_;     ///< 命令管理器
  ProcStatImplPtr proc_stat_;             ///< 进程信息统计
  SysLoggerImplPtr sys_logger_;           ///< 系统日志
  ProxyHandlerImplPtr proxy_handler_;     ///< 代理处理器
  ConsoleImplPtr console_;                ///< 控制台
  ServiceLayerPtr service_layer_;         ///< 服务管道层
  TimerFactoryImplPtr rpc_timer_factory_; ///< RPC定时器工厂
  DebugServerImplPtr debug_server_;       ///< 调试本地服务器
  InterfaceDescriptorFactoryImplPtr descriptor_factory_; ///< 接口描述工厂
  RpcProbeImplPtr rpc_probe_;                            ///< RPC探针
  StringMap registered_service_map_;      ///< 已经注册的服务
  TransportPtr proxy_transport_;          ///< proxy管道
  RpcImplPtr rpc_;                        ///< RPC实例
  StringSet installed_service_uuids_;     ///< 已经安装的服务UUID
  ModuleVector module_vec_;               ///< 模块数组，用来维持引用
  LimiterManagerPtr limiter_manager_ptr_; ///< 限流器
  BoxFlowManagerPtr box_flow_manager_ptr_;     ///< 流程管理
  ComponentFactoryPtr component_factory_;      ///< 组件工厂
  ServiceMechManagerPtr service_mech_manager_; ///< 服务发现/注册工厂
  std::string config_file_path_;               ///< 配置文件路径
  bool is_wait_stop_{false};                   ///< 等待关闭标志
  klogger::Logger *logger_{nullptr};           ///< 日志
  /**
   * 容器默认日志，在用户日志建立前使用.
   */
  klogger::Appender *console_appender_{nullptr};
  klogger::Appender *user_appender_{nullptr}; ///< 用户日志
  int argc_{0};                               ///< 命令行参数个数
  char **argv_{nullptr};                      ///< 命令行

public:
  /**
   * 构造
   */
  ServiceBox();
  /**
   * 析构
   */
  virtual ~ServiceBox();
  /**
   * 启动, 读取配置并启动所有子系统.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   * \retval true 成功
   * \retval false 失败
   */
  auto start(int argc, const char **argv) -> bool;
  /**
   * 关闭.
   *
   * \return true 成功
   * \retval false 失败
   */
  auto stop() -> bool;
  /**
   * 逻辑主循环.
   *
   * \param now 当前时间戳，毫秒
   */
  auto update(std::time_t now = 0) -> void;

  /**
   * 检测是否已经安装了某个服务
   *
   * \param uuid 服务UUID
   * \return true或false
   */
  auto is_installed(ConStrRef uuid) -> bool;

  /**
   * 注册服务.
   *
   * \param name 服务名
   * \return true 成功
   * \retval false 失败
   */
  auto register_service(ConStrRef name) -> bool;
  /**
   * 取消服务注册.
   *
   * \param name 服务名
   * \return true或false
   */
  auto unregister_service(ConStrRef name) -> bool;
  /**
   * 获取用于RPC通信的传输实例，如果没有则立即返回空实例.
   *
   * \param name 服务名
   * \return 传输实例
   */
  auto try_get_transport(ConStrRef name) -> TransportPtr;
  /**
   * 获取用于RPC通信的传输实例，在实例建立过程中将阻塞执行执行线程.
   *
   * \param name 服务名
   * \param timeout 等待时间，毫秒
   * \return 传输实例
   */
  auto get_transport_sync(ConStrRef name, std::time_t timeout) -> TransportPtr;
  /**
   * 检查是否已经停止.
   *
   * \return true或false
   */
  auto is_wait_stop() const -> bool;
  /**
   * 设置停止标志.
   *
   * \return true或false
   */
  auto set_wait_stop_flag() -> void;
  /**
   * 取得命令行参数.
   *
   * \return true或false
   */
  auto get_argument() const -> ConBoxArgumentRef;
  /**
   * 写日志.
   *
   * \param log_level 日志等级 @see klogger::Logger
   * \param log_line 日志行
   */
  virtual auto write_log_line(int log_level, ConStrRef log_line) -> void;
  /**
   * 取得配置器.
   *
   * \return 配置器
   */
  virtual auto get_config() -> BoxConfigRef override;
  /**
   * 获取上下文.
   *
   * \return 上下文
   */
  virtual auto get_context() -> ServiceContext *;
  /**
   * 获取服务注册/发现工厂管理器
   */
  virtual auto get_service_mech_manager() -> ServiceMechManager * override;
  /**
   * 获取命令管理器.
   *
   * \return 命令管理器
   */
  auto get_command_manager() -> CommandManager *;
  /**
   * 获取进程信息统计.
   *
   * \return 进程信息统计
   */
  auto get_proc_stat() -> ProcStat *;
  /**
   * 检测是否已daemon方式启动.
   *
   * \return util::FlowStatus
   */
  auto check_daemon() -> util::FlowStatus;
  /**
   * 获取服务注册接口.
   *
   * \return
   */
  auto get_service_register() -> ServiceRegister *;
  /**
   * 获取本容器已经注册的服务.
   *
   * \return
   */
  auto get_register_services() -> const StringMap &;
  /**
   * 获取系统日志.
   *
   * \return 系统日志
   */
  auto get_sys_logger() -> SysLogger *;
  /**
   * 获取代理处理器.
   *
   * \return
   */
  auto get_proxy_handler() -> rpc::ProxyHandlerImpl *;
  /**
   * 获取RPC实例.
   *
   * \return
   */
  auto get_rpc() -> rpc::Rpc *;
  /**
   * 获取控制台实例.
   *
   * \return
   */
  auto get_console() -> console::ConsoleImpl *;
  /**
   * 获取服务发现
   */
  auto get_service_finder() -> ServiceFinder *;
  /**
   * 获取ChannelLayer
   */
  auto get_service_layer() -> ServiceLayer *;
  /**
   * 获取服务更新
   */
  auto get_service_updater() -> ServiceHttpLoader *;
  /**
   * @brief 获取调试服务器
   * @return 调试服务器
   */
  auto get_debug_server() -> DebugServerImpl *;
  /**
   * 获取RPC探针.
   *
   * \return
   */
  auto get_rpc_probe() -> rpc::RpcProbe *;
  /**
   * 获取组件工厂.
   *
   * \return
   */
  auto get_component_factory() -> component::ComponentFactoryImpl *;
  /**
   * 设置服务发现
   *
   * \param service_finder_ptr 服务发现实例
   */
  auto set_service_finder(ServiceFinderPtr service_finder_ptr) -> void;

public:
  /**
   * 取得日志添加器.
   *
   * \return 日志添加器
   */
  virtual auto get_logger_appender() -> klogger::Appender * override;
  /**
   * 获取本地化实例.
   *
   * \return 本地化实例
   */
  virtual auto get_lang() -> lang::Lang * override;

protected:
  /**
   * @see BoxNetwork::on_listen.
   */
  virtual void on_listen(ConStrRef name, bool success,
                         BoxChannelPtr &channel) override;
  /**
   * @see BoxNetwork::on_accept.
   */
  virtual void on_accept(BoxChannelPtr &channel) override;
  /**
   * @see BoxNetwork::on_connect.
   */
  virtual void on_connect(ConStrRef name, bool success,
                          BoxChannelPtr &channel) override;
  /**
   * @see BoxNetwork::on_close.
   */
  virtual void on_close(BoxChannelPtr &channel) override;
  /**
   * @see BoxNetwork::on_data.
   */
  virtual void on_data(BoxChannelPtr &channel) override;

public:
  /**
   * 写入日志.
   *
   * \param id 语言ID
   * \param level 日志等级
   * \param args 日志参数
   * \return
   */
  template <typename... ARGS>
  auto write_log(lang::LangID id, int level, ARGS... args) -> void {
    const auto &fmt = get_lang()->get_lang(id);
    if (fmt.empty()) {
      return;
    }
    if (get_logger_appender()) {
      get_logger_appender()->write(level, fmt.c_str(), args...);
    } else {
      if (sys_logger_) {
        sys_logger_->log(level, fmt.c_str(), args...);
      } else {
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
#elif __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security"
#endif
        std::fprintf(stderr, fmt.c_str(), args...);
#ifdef __clang__
#pragma clang diagnostic pop
#elif __GUNC__
#pragma GCC diagnostic pop
#endif
      }
    }
  }

private:
  /**
   * @brief 检查是否有另外一个使用相同配置文件启动的实例
   * @return true或false
   */
  auto is_another_instance() -> bool;
  /**
   * 启动, 读取配置并启动所有子系统.
   *
   * \retval true 成功
   * \retval false 失败
   */
  auto start_internal() -> bool;
  /**
   * 关闭.
   *
   * \retval true 成功
   * \retval false 失败
   */
  auto stop_unsafe() -> bool;
  /**
   * 异常安全的关闭.
   *
   * \return true或false
   */
  auto stop_internal() -> bool;
  /**
   * 逻辑主循环.
   *
   * \param now 当前时间戳，毫秒
   */
  auto update_internal(std::time_t now) -> void;
  /**
   * 异常安全的主循环.
   *
   * \param now 当前时间戳，毫秒
   * \return
   */
  auto update_unsafe(std::time_t now) -> void;
  /**
   * 加载配置.
   *
   * \return retval true 成功
   * \retval false 失败
   */
  auto load_config() -> bool;
  /**
   * 根据用户配置,等待必要的服务注册到集群后才能继续运行.
   */
  auto wait_necessary_service() -> void;
  /**
   * 初始化服务发现.
   *
   * \return true或false
   */
  auto initialize_service_finder() -> bool;
  /**
   * 在用户日志建立前，首先建立默认终端日志组件.
   *
   * \return true或false
   */
  auto start_console_logger() -> bool;
  /**
   * 启动用户配置的标准日志组件.
   *
   * \param logger_config_line 用户日志配置
   * \retval true 成功
   * \retval false 失败
   */
  auto start_standard_logger(ConStrRef logger_config_line) -> bool;
  /**
   * 加载本地服务.
   *
   * \param uuid 服务UUID
   * \param file_path 服务路径
   * \retval true 成功
   * \retval false 失败
   */
  auto load_service(ConStrRef uuid, ConStrRef file_path) -> bool;
  /**
   * 加载所有本地服务.
   *
   * \param service_dir 服务所在目录
   * \retval true 成功
   * \retval false 失败
   */
  auto load_all_service(ConStrRef service_dir) -> bool;
  /**
   * 销毁所有本地服务实例.
   *
   * \retval true 成功
   * \retval false 失败
   */
  auto release_all_service() -> bool;
  /**
   * 下载所有本地bundle(.so/.dll).
   *
   * \return
   */
  auto unload_all_bundle() -> bool;
  /**
   * 启动所有监听器
   *
   * \return true或falese
   */
  auto start_all_listener() -> bool;
  /**
   * 启动一个监听器.
   *
   * \param host 地址
   * \param name 监听器名称
   * \return true或falese
   */
  auto start_listener(ConStrRef host, ConStrRef name) -> bool;
  /**
   * 打印启动信息.
   */
  auto print_startup_info() -> void;
  /**
   * 执行命令行命令并退出.
   *
   * \return
   */
  auto do_command() -> void;
  /**
   * 配置器重载.
   *
   * \return
   */
  auto register_config_reload_listener() -> void;
  /**
   * 监听器变化，只支持新增.
   *
   * \param new_config 新的配置
   * \return
   */
  auto on_listener_change(ConBoxConfigRef new_config) -> void;
  /**
   * 日志配置变化.
   *
   * \param new_config 新的配置
   * \return
   */
  auto on_logger_config_line_change(ConBoxConfigRef new_config) -> void;
  /**
   * 检测是否是客户端.
   *
   * \return
   */
  auto is_client() -> bool;
  /**
   * 解析命令行.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   * \return true或false
   */
  auto parse_command_line(int argc, const char **argv) -> bool;
  /**
   * 加载并解析配置文件.
   *
   * \return true或false
   */
  auto parse_config_file() -> bool;
  /**
   * 尝试从配置中心下载配置.
   *
   * \return true或false
   */
  auto try_download_from_config_center() -> bool;
  /**
   * 关闭日志添加器.
   *
   * \return
   */
  auto close_logger_appender() -> void;
  /**
   * 开启系统日志.
   *
   * \return util::FlowStatus
   */
  auto start_syslog() -> util::FlowStatus;
  /**
   * 启动proxy的监听器.
   *
   * \return util::FlowStatus
   */
  auto start_proxy_listener() -> util::FlowStatus;
  /**
   * 连接到代理.
   *
   * \return util::FlowStatus
   */
  auto connect_to_proxy() -> util::FlowStatus;
  /**
   * 随机从listener.host内选择一个地址.
   *
   * \return 监听地址
   */
  auto random_get_listener_host() -> std::string;
  /**
   * @brief 尝试启动脚本调试服务器
   * @return util::FlowStatus
   */
  auto try_start_debugger_server() -> util::FlowStatus;
  /**
   * 加载所有模块.
   *
   * \return
   */
  auto load_modules() -> void;
  /**
   * 启动RPC框架.
   *
   * \return
   */
  auto start_rpc_framework() -> void;
  /**
   * 建立流程.
   *
   * \param argc 参数个数
   * \param argv 参数数组
   *
   * \return
   */
  auto make_start_flow(int argc, const char **argv) -> void;
  /**
   * 建立关闭流程.
   *
   * \return
   */
  auto make_stop_flow() -> void;
  /**
   * 建立循环流程.
   *
   * \return
   */
  auto make_update_flow() -> void;
  /**
   * 设置环境变量.
   *
   * \return
   */
  auto setup_environment() -> void;
};

} // namespace service
} // namespace kratos
